/*
 * Copyright 2020-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sagacity.framework.api.model.request;

import com.sagacity.framework.api.constant.ResponseCode;
import com.sagacity.framework.exception.AppException;
import com.sagacity.framework.util.PatternUtil;
import com.sagacity.framework.util.StringUtil;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.PatternMatchUtils;

import java.util.List;
import java.util.regex.Pattern;

import static com.sagacity.framework.api.constant.ResponseCode.ARGUMENT_EMPTY;
import static com.sagacity.framework.api.constant.ResponseCode.ARGUMENT_ILLEGAL;

/**
 * 查询条件
 *
 * @author xingyun
 * @date 2020-07-04 13:37
 */
@Slf4j
@Builder
@Data
@ApiModel(description = "查询条件")
public class Criterion {
    /**
     * 实体对象字段或者表字段都可以
     */
    @ApiModelProperty("查询字段")
    private String fieldName;

    @ApiModelProperty("字段值")
    private Object fieldValue;

    @ApiModelProperty("查询条件（eq:等于、ne:不等于、gt:大于 ...）")
    private String condition;

    @ApiModelProperty("前缀")
    private String prefix;

    @ApiModelProperty("后缀")
    private String suffix;

    @ApiModelProperty("关联条件（OR、AND）")
    private String connect;

    public void handleCriterion(){
        if(StringUtil.isBlank(this.fieldName)){
            throw new AppException(ARGUMENT_EMPTY,"查询字段[fieldName]为空，请检查");
        }
        // 查询字段格式校验
        if(!PatternUtil.FIELD_NAME.matcher(this.fieldName).matches()){
            throw new AppException(ARGUMENT_ILLEGAL,"查询字段["+this.fieldName+"]格式不正确");
        }
        this.fieldName = StringUtil.toUnderlineCase(fieldName);
        // 查询条件为空校验
        if(StringUtil.isBlank(this.condition)){
            throw new AppException(ResponseCode.ARGUMENT_EMPTY,"查询条件字段[condition]不能为空");
        }
        this.condition = this.condition.toUpperCase();
        // 查询条件格式校验
        ConditionEnum conditionEnum = null;
        try{
            conditionEnum = ConditionEnum.valueOf(this.condition);
        }catch (Exception e){
            log.warn("[Criterion] 检查处理异常",e);
        }

        if(conditionEnum == null || StringUtil.isBlank(conditionEnum.condition)){
            throw new AppException(ResponseCode.ARGUMENT_EMPTY,"查询条件字段[condition]值["+this.condition+"]格式不正确");
        }
        // 处理包含:两边%
        if(ConditionEnum.LIKE.name().equals(this.condition) || ConditionEnum.NOT_LIKE.name().equals(this.condition)){
            this.fieldValue = "%"+this.fieldValue+"%";
        }
        // 包含：右边% 左不包含：右边%
        if(ConditionEnum.LEFT_LIKE.name().equals(this.condition) || ConditionEnum.LEFT_NO_TLIKE.name().equals(this.condition)){
            this.fieldValue = this.fieldValue+"%";
        }
        // 右包含：左边% 右不包含：左边%
        if(ConditionEnum.RIGHT_LIKE.name().equals(this.condition) || ConditionEnum.RIGHT_NOT_LIKE.name().equals(this.condition)){
            this.fieldValue = "%"+this.fieldValue;
        }
        if(ConditionEnum.IN.name().equals(this.condition) || ConditionEnum.NOT_IN.name().equals(this.condition)){
            if(!(this.fieldValue instanceof List)){
                throw new AppException(ARGUMENT_ILLEGAL,"查询条件[condition]与查询字段[fieldValue]格式不匹配");
            }
        }

        // 赋值完后将关联条件转换
        this.condition = conditionEnum.condition;

        if(StringUtil.isNotBlank(this.connect) && (ConnectEnum.AND.name().equals(this.connect.toLowerCase())
                || ConnectEnum.OR.name().equals(this.connect.toLowerCase()))){
            ConnectEnum connectEnum = ConnectEnum.valueOf(this.connect.toLowerCase());
            if(StringUtil.isBlank(connectEnum.connect)){
                throw new AppException(ARGUMENT_ILLEGAL,"关联条件字段[connect]值["+this.condition+"]格式非法");
            }
        }
        if(StringUtil.isNotBlank(this.prefix) && !BracketEnum.FRONT.bracket.equals(this.prefix)){
            throw new AppException(ARGUMENT_ILLEGAL,"拼接前缀[prefix]值["+this.prefix+"]格式不正确");
        }
        if(StringUtil.isNotBlank(this.suffix) && !BracketEnum.AFTER.bracket.equals(this.suffix)){
            throw new AppException(ARGUMENT_ILLEGAL,"拼接前缀[suffix]值["+this.suffix+"]格式不正确");
        }



    }

    public enum BracketEnum {
        FRONT("("),
        AFTER(")"),
        ;
        /**
         * 圆括号前后
         */
        private final String bracket;

        BracketEnum(String bracket){
            this.bracket = bracket;
        }

        public String getBracket() {
            return bracket;
        }
    }

    public enum ConnectEnum {
        AND("AND"),
        OR("OR"),
        ;
        /**
         * 条件关联（OR、AND）
         */
        private final String connect;

        ConnectEnum(String connect){
            this.connect = connect;
        }

        public String getConnect() {
            return connect;
        }

    }

    public enum ConditionEnum {
        EQ("=","等于"),
        NE("<>","不等于"),
        GT(">","大于"),
        GE(">=","大于等于"),
        LT("<","小于"),
        LE("<=","小于等于"),
        BETWEEN("BETWEEN","在...和...之间"),
        LIKE("LIKE","包含：两边%"),
        LEFT_LIKE("LIKE","左包含：右边%"),
        RIGHT_LIKE("LIKE","右包含：左边%"),
        NOT_LIKE("NOT LIKE","不包含：两边%"),
        LEFT_NO_TLIKE("NOT LIKE","左不包含：右边%"),
        RIGHT_NOT_LIKE("NOT LIKE","右不包含：左边%"),
        IN("IN","多值匹配"),
        NOT_IN("NOT IN","不是对应的多只匹配"),
        IS_NULL("IS NULL","字段等于NULL"),
        IS_NOT_NULL("IS NOT NULL","字段不等于NULL"),

        ;
        /**
         * 查询条件（>、>=、in、like等）
         */
        private final String condition;
        private final String desc;


        ConditionEnum(String condition,String desc){
            this.condition = condition;
            this.desc = desc;
        }

        public String getCondition() {
            return condition;
        }

        public String getDesc() {
            return desc;
        }
    }


}
